﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using XXF.BaseService.ServiceCenter.Dal;
using XXF.BaseService.ServiceCenter.Redis;
using XXF.BaseService.ServiceCenter.SystemRuntime;
using XXF.ProjectTool;
using XXF.Extensions;
////using XXF.BaseService.ServiceCenter.ZK;

namespace XXF.BaseService.ServiceCenter.Client.Provider
{
    /// <summary>
    /// 客户端心跳守护
    /// </summary>
    public class ClientHeatBeatProtect : IDisposable
    {
        private CancellationTokenSource cancelSource;
        private ClientContext Context;
        private object _heartbeatrunlock = new object();//客户端心跳锁，仅一个心跳任务在运行
        private RedisNetCommandListener redislistener = null;

        ////private ZKCenterWatch zk = null;

        public ClientHeatBeatProtect(ClientContext context)
        {
            try
            {
                Context = context;
                cancelSource = new CancellationTokenSource();
                System.Threading.Tasks.Task.Factory.StartNew(() =>
                {
                    HeartBeatRun();//开启心跳检查
                }, cancelSource.Token);

                ////zk = new ZKCenterWatch();

                ////zk.Register(cancelSource, Context, () =>
                ////{
                ////    return new ZkNodeInfo();
                ////});
                redislistener = new RedisNetCommandListener(SystemConfigHelper.RedisServer); redislistener.Name = "客户端" + Context.ServiceModel.servicename;
                redislistener.Register((channel, msg) =>
                {
                    RedisListenerCommand(channel, msg);
                }, cancelSource, SystemParamConfig.ServiceRedisChannel(Context.ServiceModel.id));
                LogHelper.Log(Context.ServiceModel.id, EnumLogType.Client, "客户端心跳守护初始化成功");
            }
            catch (Exception exp)
            {
                LogHelper.Error(Context.ServiceModel.id, EnumLogType.Client, "客户端心跳守护初始化失败", exp);
                throw exp;
            }
        }

        //心跳循环
        private void HeartBeatRun()
        {
            try
            {
                while (!cancelSource.IsCancellationRequested)
                {
                    HeartBeatTask();
                    System.Threading.Thread.Sleep(SystemParamConfig.Client_HeatBeat_Every_Time * 1000);
                    LogHelper.Debug(Context.ServiceModel.id, EnumLogType.Client, "客户端心跳循环一轮完毕");
                }
            }
            catch (Exception exp)
            {
                LogHelper.Error(Context.ServiceModel.id, EnumLogType.Client, "客户端心跳循环失败", exp);
            }
        }
        //心跳任务
        private void HeartBeatTask()
        {
            lock (_heartbeatrunlock)
            {
                try
                {
                    //更新节点心跳
                    SqlHelper.ExcuteSql(SystemConfigHelper.ServiceCenterConnectString, (c) =>
                    {
                        Dal.tb_service_dal servicedal = new Dal.tb_service_dal();
                        var date = servicedal.GetLastUpdateTime(c, Context.ServiceModel.id);
                        if (date == null)//服务被删除
                        {
                            Context.NodeModels.Clear();
                        }
                        if (date != null && Context.ServiceLastUpdateTime < date.Value)//服务节点有更新
                        {
                            tb_service_dal serverdal = new tb_service_dal();
                            var serviceModel = serverdal.Get(c, Context.ServiceModel.servicename);

                            tb_node_dal nodedal = new tb_node_dal();
                            var nodes = nodedal.GetAllListOnLine(c, serviceModel.id, SystemParamConfig.Node_HeatBeat_Time_Out);
                            var nodeModels = nodes;

                            Context.ServiceModel = serviceModel;
                            Context.NodeModels = nodeModels;
                            Context.ServiceLastUpdateTime = date.Value;
                        }
                    });

                }
                catch (Exception exp)
                {
                    LogHelper.Error(Context.ServiceModel.id, EnumLogType.Client, "客户端心跳任务出错", exp);
                }
            }

        }

        private void RedisListenerCommand(string channel, string msg)
        {
            try
            {
                if (!cancelSource.IsCancellationRequested)
                {
                    var command = new XXF.Serialization.JsonHelper().Deserialize<ClientNetCommand>(msg);
                    if (command.ServiceNameSpace.ToLower() == Context.ServiceModel.servicenamespace.ToLower())
                    {
                        if (command.CommandType == EnumClientCommandType.ServiceUpdate)
                        {
                            HeartBeatTask();
                        }
                    }
                    LogHelper.Debug(Context.ServiceModel.id, EnumLogType.Client, "客户端Reids监听,msg:" + msg.NullToEmpty());
                }
            }
            catch (Exception exp)
            {
                LogHelper.Error(Context.ServiceModel.id, EnumLogType.Client, "客户端Reids监听出错", exp);
            }
        }

        public void Dispose()
        {
            if (redislistener != null)
                redislistener.Dispose();
            if (cancelSource != null)
                cancelSource.Cancel();

        }
    }
}
